package com.atguigu.tingshu.album.service.impl;

import com.atguigu.tingshu.album.mapper.AlbumAttributeValueMapper;
import com.atguigu.tingshu.album.mapper.AlbumInfoMapper;
import com.atguigu.tingshu.album.mapper.AlbumStatMapper;
import com.atguigu.tingshu.album.service.AlbumInfoService;
import com.atguigu.tingshu.common.constant.SystemConstant;
import com.atguigu.tingshu.common.execption.GuiguException;
import com.atguigu.tingshu.common.util.AuthContextHolder;
import com.atguigu.tingshu.model.album.AlbumAttributeValue;
import com.atguigu.tingshu.model.album.AlbumInfo;
import com.atguigu.tingshu.model.album.AlbumStat;
import com.atguigu.tingshu.query.album.AlbumInfoQuery;
import com.atguigu.tingshu.vo.album.AlbumAttributeValueVo;
import com.atguigu.tingshu.vo.album.AlbumInfoVo;
import com.atguigu.tingshu.vo.album.AlbumListVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 注解 @Transactional(rollbackFor = Exception.class)：开启事务，Spring事务管理器会在方法执行过程中遇到异常时回滚事务。
 *
 * @author Taeyang
 * @date 2025-04-23
 */
@Slf4j
@Service
@Transactional(rollbackFor = Exception.class)
public class AlbumInfoServiceImpl extends ServiceImpl<AlbumInfoMapper, AlbumInfo> implements AlbumInfoService {

    private final AlbumInfoMapper albumInfoMapper;
    private final AlbumAttributeValueMapper albumAttributeValueMapper;
    private final AlbumStatMapper albumStatMapper;
    private final RabbitTemplate rabbitTemplate;

    @Autowired
    public AlbumInfoServiceImpl(AlbumInfoMapper albumInfoMapper, AlbumAttributeValueMapper albumAttributeValueMapper, AlbumStatMapper albumStatMapper, RabbitTemplate rabbitTemplate) {
        this.albumInfoMapper = albumInfoMapper;
        this.albumAttributeValueMapper = albumAttributeValueMapper;
        this.albumStatMapper = albumStatMapper;
        this.rabbitTemplate = rabbitTemplate;
    }

    /**
     * 新增专辑
     *
     * @param albumInfoVo 前端传递来的参数
     */
    @Override
    public void saveAlbumInfo(AlbumInfoVo albumInfoVo) {
        // 专辑的DO（Data Object）初始化
        AlbumInfo albumInfo = new AlbumInfo();
        BeanUtils.copyProperties(albumInfoVo, albumInfo);
        // 补全属性
        albumInfo.setUserId(AuthContextHolder.getUserId());
        albumInfo.setStatus(SystemConstant.ALBUM_STATUS_PASS);
        // 新增专辑数据
        if (albumInfoMapper.insert(albumInfo) <= 0) {
            // 新增失败
            throw new GuiguException(201, "新增专辑失败");
        }
        // 新增成功之后获取专辑的主键（新增完成之后MyBatisPlus会自动把主键回填到albumInfo对象中）
        Long albumInfoId = albumInfo.getId();
        // 新增专辑的标签
        saveAlbumAttrInfo(albumInfoId, albumInfoVo.getAlbumAttributeValueVoList());
        // 初始化专辑的统计数据
        initAlbumStat(albumInfoId);

        // 判断专辑的 is_open 属性是否为1
        if ("1".equals(albumInfo.getIsOpen())) {
            // 为1则将专辑数据同步到es中
            rabbitTemplate.convertAndSend("search_exchange", "album.upper", albumInfo.getId() + "");
        }
    }

    /**
     * 分页查询用户专辑
     *
     * @param pageNum        页码
     * @param pageSize       每页数量
     * @param albumInfoQuery 查询条件
     * @return 分页数据
     */
    @Override
    public Page<AlbumListVo> findUserAlbumPage(Long pageNum, Long pageSize, AlbumInfoQuery albumInfoQuery) {
        return albumInfoMapper.selectAlbumListVoByQuery(albumInfoQuery, new Page<>(pageNum, pageSize));
    }

    /**
     * 删除专辑
     *
     * @param albumId 专辑id
     */
    @Override
    public void removeAlbumInfo(Long albumId) {
        // 获取用户的id
        Long userId = AuthContextHolder.getUserId();
        // 删除专辑表数据（需要验证是专辑的所属人在删除自己的专辑）
        if (albumInfoMapper.delete(new LambdaQueryWrapper<AlbumInfo>().eq(AlbumInfo::getUserId, userId).eq(AlbumInfo::getId, albumId)) < 0) {
            throw new GuiguException(201, "删除专辑数据失败");
        }
        // 删除统计表数据
        if (albumStatMapper.delete(new LambdaQueryWrapper<AlbumStat>().eq(AlbumStat::getAlbumId, albumId)) < 0) {
            throw new GuiguException(201, "删除专辑统计数据失败");
        }
        // 删除标签表数据
        if (albumAttributeValueMapper.delete(new LambdaQueryWrapper<AlbumAttributeValue>().eq(AlbumAttributeValue::getAlbumId, albumId)) < 0) {
            throw new GuiguException(201, "删除标签数据失败");
        }
        // 将专辑数据从到es中删除
        rabbitTemplate.convertAndSend("search_exchange", "album.down", albumId + "");

    }

    /**
     * 根据专辑id查询详细信息进行表单回显
     *
     * @param albumId 专辑id
     * @return 专辑详细信息
     */
    @Override
    public AlbumInfo getAlbumInfo(Long albumId) {
        // 获取用户id
        Long userId = AuthContextHolder.getUserId();
        // 查询专辑的数据
        AlbumInfo albumInfo = albumInfoMapper.selectOne(
            new LambdaQueryWrapper<AlbumInfo>().eq(AlbumInfo::getUserId, userId).eq(AlbumInfo::getId, albumId));
        if (albumInfo == null) {
            throw new GuiguException(201, "专辑不存在");
        }
        // 查询专辑的标签数据
        List<AlbumAttributeValue> albumAttributeValues = albumAttributeValueMapper.selectList(new LambdaQueryWrapper<AlbumAttributeValue>().eq(AlbumAttributeValue::getAlbumId, albumId));
        // 保存专辑的标签数据
        albumInfo.setAlbumAttributeValueVoList(albumAttributeValues);
        // 返回
        return albumInfo;
    }

    /**
     * 根据专辑id修改专辑信息
     *
     * @param albumId     专辑id
     * @param albumInfoVo 前端传递过来的专辑信息对象
     */
    @Override
    public void updateAlbumInfo(Long albumId, AlbumInfoVo albumInfoVo) {
        // 获取用户id
        Long userId = AuthContextHolder.getUserId();
        // 创建DO对象
        AlbumInfo albumInfo = new AlbumInfo();
        BeanUtils.copyProperties(albumInfoVo, albumInfo);
        // 填充userId
        albumInfo.setUserId(userId);
        // 将专辑的数据进行修改album_info
        int i = albumInfoMapper.update(albumInfo, new LambdaQueryWrapper<AlbumInfo>().eq(AlbumInfo::getUserId, userId).eq(AlbumInfo::getId, albumId));
        if (i < 0) {
            throw new GuiguException(201, "修改专辑信息失败");
        }
        // 删除旧的标签数据，新增新的标签数据
        i = albumAttributeValueMapper.delete(new LambdaQueryWrapper<AlbumAttributeValue>().eq(AlbumAttributeValue::getAlbumId, albumId));
        if (i < 0) {
            throw new GuiguException(201, "修改专辑信息失败");
        }
        // 新增标签
        saveAlbumAttrInfo(albumId, albumInfoVo.getAlbumAttributeValueVoList());


        // es同步数据
        if ("1".equals(albumInfo.getIsOpen())) {
            // 为1则将专辑数据同步到es中
            rabbitTemplate.convertAndSend("search_exchange", "album.upper", albumId + "");
        } else {
            // 为1则将专辑数据同步到es中
            rabbitTemplate.convertAndSend("search_exchange", "album.down", albumId + "");
        }
    }

    /**
     * 新增声音时通过当前登录的用户id查询本id下的所有专辑
     *
     * @return 专辑列表
     */
    @Override
    public List<AlbumInfo> findUserAllAlbumList() {
        // 获取用户id
        Long userId = AuthContextHolder.getUserId();
        // 查询这个用户可用的全部声音，默认分页
        return albumInfoMapper.selectPage(new Page<>(1, 10), new LambdaQueryWrapper<AlbumInfo>().eq(AlbumInfo::getUserId, userId).orderByDesc(AlbumInfo::getId)).getRecords();
    }

    /**
     * 查询专辑的统计数据
     *
     * @param id
     * @return
     */
    @Override
    public Map<String, Object> getAlbumStat(Long id) {
        // 查询专辑的全部统计数据
        List<AlbumStat> albumStatList = albumStatMapper.selectList(new LambdaQueryWrapper<AlbumStat>().eq(AlbumStat::getAlbumId, id));
        // 将list转换为map
        return albumStatList
            .stream()
            .collect(Collectors.toMap(
                key -> key.getStatType(), value -> value.getStatNum()
            ));
    }

    /**
     * 查询专辑的标签属性列表
     *
     * @param id
     * @return
     */
    @Override
    public List<AlbumAttributeValue> getAlbumAttributeValueList(Long id) {
        return albumAttributeValueMapper.selectList(new LambdaQueryWrapper<AlbumAttributeValue>().eq(AlbumAttributeValue::getAlbumId, id));
    }


    /**
     * 初始化专辑的统计数据
     *
     * @param albumInfoId 专辑id
     */
    private void initAlbumStat(Long albumInfoId) {
        // 初始化DO
        AlbumStat albumStat = new AlbumStat();
        // 设置统计数据对应的专辑id
        albumStat.setAlbumId(albumInfoId);
        // 设置统计数据的量
        albumStat.setStatNum(0);

        // 播放量
        albumStat.setStatType(SystemConstant.ALBUM_STAT_PLAY);
        albumStatMapper.insert(albumStat);
        // 订阅量
        // 新增之后MyBatisPlus会自动把主键回填到albumStat对象中,再次创建新对象又很麻烦，所以直接设置刚刚新建的那一条数据的主键为null，然后更改修改直接新增即可
        albumStat.setId(null);
        albumStat.setStatType(SystemConstant.ALBUM_STAT_SUBSCRIBE);
        albumStatMapper.insert(albumStat);
        // 购买量
        albumStat.setId(null);
        albumStat.setStatType(SystemConstant.ALBUM_STAT_BROWSE);
        albumStatMapper.insert(albumStat);
        // 评论数
        albumStat.setId(null);
        albumStat.setStatType(SystemConstant.ALBUM_STAT_COMMENT);
        albumStatMapper.insert(albumStat);
    }

    /**
     * 保存专辑的标签信息
     *
     * @param albumInfoId               专辑id
     * @param albumAttributeValueVoList 标签信息列表
     */
    private void saveAlbumAttrInfo(Long albumInfoId, List<AlbumAttributeValueVo> albumAttributeValueVoList) {
        // 遍历新增
        albumAttributeValueVoList.forEach(albumAttributeValueVo -> {
            // 初始化标签DO
            AlbumAttributeValue albumAttributeValue = new AlbumAttributeValue();
            albumAttributeValue.setAlbumId(albumInfoId);
            BeanUtils.copyProperties(albumAttributeValueVo, albumAttributeValue);
            // 新增本条标签数据
            if (albumAttributeValueMapper.insert(albumAttributeValue) <= 0) {
                throw new GuiguException(201, "新增专辑标签失败");
            }
        });
    }
}
